import static org.eclipse.leshan.LwM2mId.*;
import static org.eclipse.leshan.client.object.Security.*;

import models.Device;
import models.RandomTemperatureSensor;
import models.WaterMeterSensor;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.leshan.LwM2m;
import org.eclipse.leshan.client.californium.LeshanClient;
import org.eclipse.leshan.client.californium.LeshanClientBuilder;
import org.eclipse.leshan.client.object.Server;
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.core.model.ObjectLoader;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.StaticModel;
import org.eclipse.leshan.core.request.BindingMode;
import util.Configuration;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    private static final String[] modelPaths = new String[] { "Generic Sensor.xml", "3303.xml" };

    // Object Id
    private static final int WATER_METER = 3300;
    private static final int TEMPERATURE = 3303;

    public static void main(String[] args) {

        Options options = new Options();

        options.addOption("lh", "coaphost", true, "Set the local CoAP address.\n  Default: any local address.");
        options.addOption("u", true, String.format("Set the LWM2M or Bootstrap server URL.\nDefault: localhost:%d.",
                LwM2m.DEFAULT_COAP_PORT));

        CommandLine cl;
        try {
            cl = new DefaultParser().parse(options, args);
        } catch (ParseException e) {
            System.err.println("Parsing failed.  Reason: " + e.getMessage());
            return;
        }

        String localhost;
        if (cl.hasOption("lh")) {
            localhost = cl.getOptionValue("lh");
        } else {
            localhost = "localhost";
        }

        String serverURI;
        if (cl.hasOption("u")) {
            serverURI = "coap://" + cl.getOptionValue("u") + ":5683";
        } else {
            serverURI = "coap://" + "localhost" + ":5683";
        }

        System.out.println(serverURI);

        LeshanClientBuilder builder = new LeshanClientBuilder(Configuration.endpoint);

        List<ObjectModel> models = ObjectLoader.loadDefault();
        models.addAll(ObjectLoader.loadDdfResources("/models", modelPaths));

        Device deviceObject = new Device();

        // initiate object instances
        ObjectsInitializer initializer = new ObjectsInitializer(new StaticModel(models));
        initializer.setInstancesForObject(SECURITY, noSec(serverURI, 123));
        initializer.setInstancesForObject(SERVER, new Server(123, 300, BindingMode.U, false));
        initializer.setInstancesForObject(DEVICE, deviceObject);
        initializer.setInstancesForObject(WATER_METER, new WaterMeterSensor());
        initializer.setInstancesForObject(TEMPERATURE, new RandomTemperatureSensor());

        // initiate additional arguments map
        Map<String, String> additionalMap = new HashMap<>();
        additionalMap.put("model", deviceObject.getModelNumber());

        builder.setAdditionalAttributes(additionalMap);

        List<LwM2mObjectEnabler> enablers = initializer.createAll();

        NetworkConfig coapConfig = NetworkConfig.getStandard();

        builder.setCoapConfig(coapConfig);
        builder.setLocalAddress(localhost, 0);
        builder.setObjects(enablers);

        final LeshanClient client = builder.build();
        client.start();

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                client.destroy(true);
            }
        });
    }
}
